package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.login.GuiGuLogin;
import com.atguigu.tingshu.model.account.UserAccount;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;


    /**
     * 保存专辑下声音
     *
     * @param userId      用户ID
     * @param trackInfoVo 声音信息VO对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(Long userId, TrackInfoVo trackInfoVo) {
        //1.保存声音
        //1.1 将前端提交声音VO对象转为声音PO对象
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //1.2 为声音对象中基本属性赋值：用户ID、声音来源、声音审核状态（审核通过）
        trackInfo.setUserId(userId);
        trackInfo.setSource("1");
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        //1.3 根据专辑ID查询专辑信息得到专辑已有声音数量，计算出新增声音序号
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        //1.4 根据文件唯一标识远程调用腾讯点播平台接口获取音频文件信息（音频时长、大小、音频类型）
        TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        //1.5 保存声音得到声音ID
        trackInfoMapper.insert(trackInfo);
        Long trackId = trackInfo.getId();

        //2.新增声音统计信息
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);

        //3.更新专辑包含声音数量
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 新增专辑统计信息
     *
     * @param trackId  声音ID
     * @param statType 统计类型
     * @param statNum  统计数值
     */
    @Override
    public void saveTrackStat(Long trackId, String statType, int statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 分页获取当前登录用户声音列表
     *
     * @param pageInfo       分页对象
     * @param trackInfoQuery 查询条件
     * @return 分页对象
     */
    @Override
    public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.getUserTrackPage(pageInfo, trackInfoQuery);
    }

    /**
     * 修改声音
     *
     * @param id          声音ID
     * @param trackInfoVo 声音VO对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        //1.根据声音ID查询声音对象-判断声音是否变更
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        //1.2 变更前音频文件唯一标识
        String mediaFileIdBefore = trackInfo.getMediaFileId();
        //1.1 最新提交音频文件唯一标识
        String mediaFileIdAfter = trackInfoVo.getMediaFileId();
        //1.2 拷贝属性
        BeanUtil.copyProperties(trackInfoVo, trackInfo);

        //2.如果声音变更，获取最新声音相关音频信息（时长、大小、类型）为PO对象赋值
        if (!mediaFileIdBefore.equals(mediaFileIdAfter)) {
            TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(mediaFileIdAfter);
            if (trackMediaInfo != null) {
                trackInfo.setMediaType(trackMediaInfo.getType());
                trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
                trackInfo.setMediaSize(trackMediaInfo.getSize());
                //4.将变更前声音文件从云点播平台删除
                vodService.deleteTrackMedia(mediaFileIdBefore);
            }
        }
        //3.更新声音
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 根据ID删除声音
     *
     * @param id 声音ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //1.根据要删除声音ID查询声音对象-获取当前声音序号用于更新其他声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        Integer orderNum = trackInfo.getOrderNum();
        //2.删除声音-逻辑删除
        trackInfoMapper.deleteById(id);

        //3.将比删除声音序号大的声音序号进行递减
        trackInfoMapper.updateTrackNum(trackInfo.getAlbumId(), orderNum);

        //4.删除声音统计记录
        LambdaQueryWrapper<TrackStat> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackStat::getTrackId, id);
        trackStatMapper.delete(queryWrapper);

        //5.更新专辑包含声音数量减一
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        //6.删除云点播平台声音文件
        vodService.deleteTrackMedia(trackInfo.getMediaFileId());
    }

    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 获取当前用户分集购买声音列表
     *
     * @param trackId 声音ID
     * @return [{name:"本集", price:0.2, trackCount:1},{name:"后10集", price:2, trackCount:10},...,{name:"全集", price:*, trackCount:*}]
     */
    @Override
    public List<Map<String, Object>> getUserWaitBuyTrackPayList(Long trackId) {
        //1.根据声音ID查询声音对象-得到专辑ID跟声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        //2.根据专辑ID+当前声音序号查询大于当前声音待购买声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
        queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(waitBuyTrackList)) {
            throw new GuiguException(400, "该专辑下没有符合购买要求声音");
        }
        //3.远程调用"用户服务"获取用户已购买声音ID集合
        List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();

        //4.将待购买声音列表中用户已购买声音排除掉-得到实际代购买声音列表
        if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
            waitBuyTrackList = waitBuyTrackList.stream()
                    .filter(waitTrackInfo -> !userPaidTrackIdList.contains(waitTrackInfo.getId())) //排除掉已购声音ID
                    .collect(Collectors.toList());
        }
        //5.基于实际购买声音列表长度，动态构建分集购买对象
        List<Map<String, Object>> mapList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(waitBuyTrackList)) {
            //5.1 根据专辑ID查询专辑得到单集价格
            AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
            BigDecimal price = albumInfo.getPrice();
            //5.1 构建本集购买对象
            Map<String, Object> currMap = new HashMap<>();
            currMap.put("name", "本集");
            currMap.put("price", price);
            currMap.put("trackCount", 1);
            mapList.add(currMap);
            //5.2 判断待购买声音数量 数量<10 动态展示后count集合 价格=count*price 数量=count
            int count = waitBuyTrackList.size();

            //5.3 数量>=10 固定显示后10集 价格=10*price 数量=10
            //if (count >= 10) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后10集");
            //    map.put("price", price.multiply(new BigDecimal("10")));
            //    map.put("trackCount", 10);
            //    mapList.add(map);
            //}
            ////5.3 数量>10 and 数量<20 动态展示：后count集合（全集） 价格=count*price 数量=count  相当于全集
            //if (count > 10 && count < 20) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后"+count+"集(全集)");
            //    map.put("price", price.multiply(new BigDecimal(count)));
            //    map.put("trackCount", count);
            //    mapList.add(map);
            //}
            //
            ////5.4 数量>=20 固定显示后20集 价格=20*price 数量=20
            //if (count >= 20) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后20集");
            //    map.put("price", price.multiply(new BigDecimal("20")));
            //    map.put("trackCount", 20);
            //    mapList.add(map);
            //}
            ////5.4 数量>20 and 数量<30 动态展示：后count集合（全集） 价格=count*price 数量=count  相当于全集
            //if (count > 20 && count < 30) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后"+count+"集(全集)");
            //    map.put("price", price.multiply(new BigDecimal(count)));
            //    map.put("trackCount", count);
            //    mapList.add(map);
            //}
            ////5.5 数量>=30 固定显示后30集 价格=30*price 数量=30
            //if (count >= 30) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后30集");
            //    map.put("price", price.multiply(new BigDecimal("30")));
            //    map.put("trackCount", 30);
            //    mapList.add(map);
            //}
            ////5.5 数量>30 and 数量<40 动态展示：后count集合（全集） 价格=count*price 数量=count  相当于全集
            //if (count > 30 && count < 40) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后"+count+"集(全集)");
            //    map.put("price", price.multiply(new BigDecimal(count)));
            //    map.put("trackCount", count);
            //    mapList.add(map);
            //}
            //
            ////5.5 数量>=40 固定显示后40集 价格=40*price 数量=40
            //if (count >= 40) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后40集");
            //    map.put("price", price.multiply(new BigDecimal("40")));
            //    map.put("trackCount", 40);
            //    mapList.add(map);
            //}
            ////5.5 数量>40 and 数量<50 动态展示：后count集合（全集） 价格=count*price 数量=count  相当于全集
            //if (count > 40 && count < 50) {
            //    Map<String, Object> map = new HashMap<>();
            //    map.put("name", "后"+count+"集(全集)");
            //    map.put("price", price.multiply(new BigDecimal(count)));
            //    map.put("trackCount", count);
            //    mapList.add(map);
            //}

            for (int i = 10; i <= 50; i += 10) {
                //判断数量>i 固定显示后i集
                if (count > i) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", "后" + i + "集");
                    map.put("price", price.multiply(new BigDecimal(i)));
                    map.put("trackCount", i);
                    mapList.add(map);
                } else {
                    //反之全集（动态构建后count集合）
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", "后" + count + "集（全集）");
                    map.put("price", price.multiply(new BigDecimal(count)));
                    map.put("trackCount", count);
                    mapList.add(map);
                    break;
                }
            }
        }
        return mapList;
    }


    /**
     * 查询当前用户待购买声音列表（加用户已购买声音排除掉）
     *
     * @param userId 用户ID
     * @param trackId    声音ID
     * @param trackCount 数量
     * @return
     */
    @Override
    public List<TrackInfo> getWaitBuyTrackInfoList(Long userId, Long trackId, int trackCount) {
        //1.根据声音ID查询声音对象-得到专辑ID跟声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

        //2.远程调用"用户服务"获取用户已购买声音ID集合
        List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();

        //3.根据专辑ID+当前声音序号查询大于当前声音待购买声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
        queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        //3.1 去掉已购买过声音
        if(CollectionUtil.isNotEmpty(userPaidTrackIdList)){
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        //3.2 限制购买数量(用户选择购买数量)
        queryWrapper.last("limit "+trackCount);
        //3.3 只查询指定列：封面图片、声音名称、声音ID、所属专辑ID
        queryWrapper.select(TrackInfo::getId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
        //3.4 对声音进行排序：按照序号升序
        queryWrapper.orderByAsc(TrackInfo::getOrderNum);
        List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(waitBuyTrackList)) {
            throw new GuiguException(400, "该专辑下没有符合购买要求声音");
        }
        return waitBuyTrackList;
    }
}
